/*
 * @file          device.c
 * @author        Gavin Liu
 * @version       v0.1
 * @brief         a implementation of device management,it is easy to port rtos environment.
 *                
 * Change Logs:
 * Date           Author       Notes
 * 2016-05-22     Gavin Liu    release
 */

#ifndef _DEVICE_H_
#define _DEVICE_H_

#include "stdint.h"

#ifndef LT_MAX_OBJ_NAME_LEN
#define LT_MAX_OBJ_NAME_LEN 16
#endif

#ifndef NULL
#define NULL (0)
#endif

#ifdef __cplusplus
extern "C" {
#endif
    
#define LT_DEV_NUM_MAX                  64
    
#define LT_DEVICE_FLAG_CLOSE            (uint16_t)0x0000          /**< device is closed */	
#define LT_DEVICE_FLAG_RDONLY           (uint16_t)0x0001          /**< read only access */	
#define LT_DEVICE_FLAG_WRONLY           (uint16_t)0x0002          /**< write only access */	
#define LT_DEVICE_FLAG_RDWR             (uint16_t)0x0003          /**< read and write */
#define LT_DEVICE_FLAG_POLL             (uint16_t)0x0004          /**< block */
	
#define LT_DEVICE_FLAG_REMOVABLE        (uint16_t)0x0008          /**< removable device */	
#define LT_DEVICE_FLAG_STANDALONE       (uint16_t)0x0010          /**< standalone device */	
#define LT_DEVICE_FLAG_ACTIVATED        (uint16_t)0x0020          /**< device is activated */	
#define LT_DEVICE_FLAG_SUSPENDED        (uint16_t)0x0040          /**< device is suspended */	
#define LT_DEVICE_FLAG_STREAM           (uint16_t)0x0080          /**< stream mode */	
#define LT_DEVICE_FLAG_INT_RX           (uint16_t)0x0100          /**< INT mode on Rx */	
#define LT_DEVICE_FLAG_DMA_RX           (uint16_t)0x0200          /**< DMA mode on Rx */	
#define LT_DEVICE_FLAG_INT_TX           (uint16_t)0x0400          /**< INT mode on Tx */	
#define LT_DEVICE_FLAG_DMA_TX           (uint16_t)0x0800          /**< DMA mode on Tx */
	
#define LT_DEVICE_CTRL_CONFIG           (uint16_t)0x0001    		/* configure device */
#define LT_DEVICE_CTRL_SET_INT          (uint16_t)0x0002    		/* enable receive irq */	
#define LT_DEVICE_CTRL_CLR_INT          (uint16_t)0x0004    		/* disable receive irq */	
#define LT_DEVICE_CTRL_GET_INT          (uint16_t)0x0008	
#define LT_DEVICE_CTRL_BLK_GETGEOME   	(uint16_t)0x0010
#define LT_DEVICE_CTRL_FIFOFLUSH        (uint16_t)0x0020

#define O_RDONLY    LT_DEVICE_FLAG_RDONLY  
#define O_WRONLY    LT_DEVICE_FLAG_WRONLY  
#define O_RDWR      LT_DEVICE_FLAG_RDWR	
	
enum lt_device_class_type
{
    LT_Device_Class_Char = 0,                           /**< character device */
    LT_Device_Class_Block,                              /**< block device */
    LT_Device_Class_NetIf,                              /**< net interface */
	LT_Device_Class_I2CDevice,                          /**< I2C device */
    LT_Device_Class_SPIDevice,                          /**< SPI device */
};
	

	
struct lt_dev_s
{
    char name[LT_MAX_OBJ_NAME_LEN];
    enum lt_device_class_type type;                     /**< device type */

    uint16_t                   flag;                     /**< device flag */
    uint16_t                   open_flag;                /**< device open flag */

    uint8_t                	   ref_count;                /**< reference count */
    uint8_t                	   device_id;                /**< 0 - 255 */

    /* common device interface */
    int32_t  (*init)   (struct lt_dev_s *dev);
    int32_t  (*deinit) (struct lt_dev_s *dev);
    int32_t  (*open)   (struct lt_dev_s *dev, uint16_t oflag);
    int32_t  (*close)  (struct lt_dev_s *dev);
    int32_t  (*read)   (struct lt_dev_s *dev, void *buffer, int32_t size,int32_t pos);
    int32_t  (*write)  (struct lt_dev_s *dev, const void *buffer, int32_t size,int32_t pos);
    int32_t  (*ioctl)  (struct lt_dev_s *dev, uint32_t cmd, void *args);

    void                     *priv_data;                /**<  private data */
};

struct lt_dev_info_s{
    char       name[LT_MAX_OBJ_NAME_LEN];
    uint16_t   flag;                     /**< device flag */
    uint16_t   open_flag;                /**< device open flag */

    uint8_t    ref_count;                /**< reference count */
};

/**
 * block device geometry structure
 */
struct lt_dev_block_geometry_s
{
    uint32_t sector_count;                           /**< count of sectors */
    uint32_t bytes_per_sector;                       /**< number of bytes per sector */
    uint32_t block_size;                             /**< number of bytes to erase one block */
};

/**
 * sector arrange struct on block device
 */
struct lt_dev_block_sectors_s
{
    uint32_t sector_begin;                           /**< begin sector */
    uint32_t sector_end;                             /**< end sector   */
};


int32_t  lt_dev_register(struct lt_dev_s *dev,const char *name,uint16_t flags);
int32_t  lt_dev_unregister(struct lt_dev_s *dev);

void     lt_dev_init(void);
int32_t  lt_dev_open(char *name,uint16_t oflag);
int32_t  lt_dev_close(int32_t fd);
int32_t  lt_dev_read(int32_t fd, void *buffer, int32_t size,int32_t pos);
int32_t  lt_dev_write(int32_t fd, const void *buffer, int32_t size,int32_t pos);
int32_t  lt_dev_ioctl(int32_t fd, uint32_t cmd, void *args);
int32_t  lt_dev_get_info(struct lt_dev_info_s *info,int num);
int32_t  lt_dev_get_num(void);

#ifdef __cplusplus
}
#endif

#endif
